package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.itheima.mapper.TSeckillArticleMapper;
import com.itheima.model.TOrder;
import com.itheima.mapper.TOrderMapper;
import com.itheima.model.TSeckillArticle;
import com.itheima.service.ITOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Wrapper;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author astupidcoder
 * @since 2021-05-15
 */
@Service
@Transactional
public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> implements ITOrderService {

    @Autowired
    private TOrderMapper tOrderMapper;

//    //Reentrant可重入 Locak锁
//    private Lock lock = new ReentrantLock();

    @Autowired
    private TSeckillArticleMapper tSeckillArticleMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    private static AtomicInteger count = new AtomicInteger(0);

    private static final Long SUCCESS = 1L;
    // 获取锁的超时时间
    private static final long timeout = 10000;

    /**
     * @author 陈衍汀
     * @Date 2021/5/15 22:08
     * @param userId 用户编号
     * @param arcId 商品编号
     * @param totalPrice 订单总额
     * @return java.lang.String
     * @Description
    */
    @Override
    public synchronized String POrder1(String userId, String arcId, String totalPrice) throws Exception {
        //方案一
        // 从数据库查询库存
        TSeckillArticle tSeckillArticle = tSeckillArticleMapper.selectStockNumByArticleId(arcId);
        Integer articleStockNum = tSeckillArticle.getArticleStockNum();
        if (articleStockNum > 0) {
            //库存减一
            tSeckillArticle.setArticleStockNum(--articleStockNum);
            //修改数据库库存
            tSeckillArticleMapper.updateById(tSeckillArticle);

            //订单表添加订单
            TOrder tOrder = new TOrder();
            tOrder.setId(UUID.randomUUID().toString().substring(10));
            tOrder.setUserId(userId);
            tOrder.setArticleId(arcId);
            tOrder.setAddTime(LocalDateTime.now());
            tOrder.setOrderStatus(0);
            tOrderMapper.insert(tOrder);
            return "下单成功";
        }
        return "库存不足";



        //方案二
        // 先将库存减一 再返回
//        Long articleStockNum = redisTemplate.opsForValue().decrement("order_" + arcId);
//
//        if (articleStockNum > -1) {
//            //进行下单
//            TOrder tOrder = new TOrder();
//            tOrder.setId(UUID.randomUUID().toString().substring(10));
//            tOrder.setUserId(userId);
//            tOrder.setArticleId(arcId);
//            tOrder.setAddTime(LocalDateTime.now());
//            tOrder.setOrderStatus(0);
//            tOrderMapper.insert(tOrder);
//            return "下单成功";
//        } else {
//            return "库存不足";
//        }





        //分布式锁 但是无法防止超卖
        // 用户开抢时间
//        long startTime = System.currentTimeMillis();
        // 未抢到情况下，10内继续获取锁
//        while ((startTime + timeout) >= System.currentTimeMillis()) {
//            if (setNx("grabbing"+arcId, userId, 60)) {
//                try {
                    // 查询库存
//            TSeckillArticle tSeckillArticle = tSeckillArticleMapper.selectStockNumByArticleId(arcId);
//            Integer articleStockNum = tSeckillArticle.getArticleStockNum();
//            System.out.println(articleStockNum);

                    // 查询库存
//                    Integer articleStockNum = (Integer)redisTemplate.opsForValue().get("order_"+arcId);


//                    System.out.println(articleStockNum);

//                    if (articleStockNum == null) {
//                        TSeckillArticle tSeckillArticle = tSeckillArticleMapper.selectStockNumByArticleId(arcId);
//                        articleStockNum = tSeckillArticle.getArticleStockNum();
//                        redisTemplate.opsForValue().setIfAbsent("order_"+arcId, articleStockNum, 5, TimeUnit.MINUTES);
//
//                    }
//                    if (articleStockNum > 1) {
//                        // 扣减库存
//
//                        //进行下单
//                        TOrder tOrder = new TOrder();
//                        tOrder.setId(UUID.randomUUID().toString().substring(10));
//                        tOrder.setUserId(userId);
//                        tOrder.setArticleId(arcId);
//                        tOrder.setAddTime(LocalDateTime.now());
//                        tOrder.setOrderStatus(0);
//                        tOrderMapper.insert(tOrder);
//                        redisTemplate.opsForValue().setIfPresent("order_"+arcId, --articleStockNum);
//                        return "下单成功";
//                    } else {
//                        return "卖完了";
//                    }
//                } catch (Exception e) {
//                    throw new Exception(e.getMessage());
//                } finally {
//                    delNx("grabbing"+arcId, userId);
//                }
//            }
//        }

    }

    @Override
    public String initializationStockNum(String articleId) {
        TSeckillArticle tSeckillArticle = tSeckillArticleMapper.selectStockNumByArticleId(articleId);
        Integer articleStockNum = tSeckillArticle.getArticleStockNum();
        redisTemplate.opsForValue().setIfAbsent("order_"+articleId, articleStockNum+"", 5, TimeUnit.MINUTES);
        return "初始化成功";
    }

    /***
     * 设置锁
     * @param key
     * @param val
     * @param expireTime
     * @return
     */
    private Boolean setNx(String key, String val, long expireTime) {
//        System.out.println(key +" "+val);
        // 设置键值对 如果不存在
        Boolean ret = redisTemplate.opsForValue().setIfAbsent(key, val, expireTime, TimeUnit.SECONDS);
        return ret;
    }


    /***
     * 删除锁
     * @param key
     * @param val
     * @return
     */
    private Boolean delNx(String key, String val) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
        Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), val);
        if (SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }

    @Scheduled(cron = "0/10 * * * * ?")
    public void synchronizationStockNum() {
        // 查询库存
        // 同步操作执行
        String articleStockNum = (String)redisTemplate.opsForValue().get("order_"+100);

        if (articleStockNum != null) {
            Long l = Long.valueOf(articleStockNum);
            if (l < 0) {
                l = 0L;
            }
            TSeckillArticle tSeckillArticle = new TSeckillArticle();
            tSeckillArticle.setId("1");
            tSeckillArticle.setArticleStockNum(l.intValue());
            tSeckillArticleMapper.updateById(tSeckillArticle);
        }
    }
}
